#pragma once


#include "qtime.h"
#include "qerror.h"
#include "qabstractfile.h"
using namespace micro::utils;


const TCHAR QSTRTERMINATOR	= _T( '\0' );
const TCHAR QBACKSLASH		= _T( '\\' );
const TCHAR QSLASH			= _T( '/' );
const TCHAR QDIRDELIMITER	=  QBACKSLASH; //_T('\\');
const TCHAR QSEPARATORS[]	= _T( "/\\" );
const TCHAR QANYSTRING[]	= _T( "*" );
const TCHAR QDOT			= _T( '.' );
const TCHAR QENDL			= _T( '\n' );

const TCHAR QCOLON			= _T( ':' );
const TCHAR QDOTSTR[]		= _T( "." );
const TCHAR QDOTDOT[]		= _T( ".." );
const TCHAR QDOTDOTDOT[]	= _T( "..." );
const TCHAR QANYFILE[]		= _T( "*.*" );


const TCHAR QGOTOROOTFOLDER	= _T( '\\' );
const TCHAR QEMPTYSTR[]		= _T( "" );
const TCHAR QPREFFIX[]		= _T( "\\??\\" );

const TCHAR QPREFFIX2[]		= _T( "\\\\?\\" );

//multi streams
/////////////////////////////////////////////////////////////////////////////////////


namespace micro
{
namespace files
{
 

//typedef INT NTSTATUS;
typedef struct  IO_STATUS_BLOCK
{
    NTSTATUS Status;
    ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;


typedef enum FILE_INFORMATION_CLASS
{
    FileDirectoryInformation = 1,     // 1
    FileFullDirectoryInformation,     // 2
    FileBothDirectoryInformation,     // 3
    FileBasicInformation,             // 4
    FileStandardInformation,          // 5
    FileInternalInformation,          // 6
    FileEaInformation,                // 7
    FileAccessInformation,            // 8
    FileNameInformation,              // 9
    FileRenameInformation,            // 10
    FileLinkInformation,              // 11
    FileNamesInformation,             // 12
    FileDispositionInformation,       // 13
    FilePositionInformation,          // 14
    FileModeInformation = 16,         // 16
    FileAlignmentInformation,         // 17
    FileAllInformation,               // 18
    FileAllocationInformation,        // 19
    FileEndOfFileInformation,         // 20
    FileAlternateNameInformation,     // 21
    FileStreamInformation,            // 22
    FilePipeInformation,              // 23
    FilePipeLocalInformation,         // 24
    FilePipeRemoteInformation,        // 25
    FileMailslotQueryInformation,     // 26
    FileMailslotSetInformation,       // 27
    FileCompressionInformation,       // 28
    FileObjectIdInformation,          // 29
    FileCompletionInformation,        // 30
    FileMoveClusterInformation,       // 31
    FileQuotaInformation,             // 32
    FileReparsePointInformation,      // 33
    FileNetworkOpenInformation,       // 34
    FileAttributeTagInformation,      // 35
    FileTrackingInformation           // 36
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;


#pragma pack(push, 4)
typedef struct _FILE_STREAM_INFORMATION
{
    // Information Class 22
    ULONG NextEntryOffset;
    ULONG StreamNameLength;
    LARGE_INTEGER EndOfStream;
    LARGE_INTEGER AllocationSize;
    WCHAR StreamName[1];
} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;
#pragma pack(pop)


#define STREAMBUFFERSIZE			32768
#define STATUS_SUCCESS				((NTSTATUS)0x00000000L) // ntsubauth
#define STATUS_BUFFER_OVERFLOW		((NTSTATUS)0x80000005L)

NTSTATUS NTAPI NtQueryInformationFile(
    IN HANDLE FileHandle,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FileInformation,
    IN ULONG Length,
    IN FILE_INFORMATION_CLASS FileInformationClass );


/////////////////////////////////////////////////////////////////////////////////


struct QFileStatus
{
    QTime m_ctime;          // creation date/time of file
    QTime m_mtime;          // last modification date/time of file
    QTime m_atime;          // last access date/time of file
    ULONGLONG m_size;            // logical size of file in bytes
    BYTE m_attribute;       // logical OR of CFile::Attribute enum values
    BYTE _m_padding;        // pad the structure to a WORD
    TCHAR m_szFullName[MAX_PATH]; // absolute path name


};



class QFile : public QAbstractFile
{
public:
// Flag values



    enum OpenFlags
    {
        modeRead =         ( int ) 0x00000,
        modeWrite =        ( int ) 0x00001,
        modeReadWrite =    ( int ) 0x00002,
        shareCompat =      ( int ) 0x00000,
        shareExclusive =   ( int ) 0x00010,
        shareDenyWrite =   ( int ) 0x00020,
        shareDenyRead =    ( int ) 0x00030,
        sharePermitAll =   ( int ) 0x00040,
        modeNoInherit =    ( int ) 0x00080,
#ifdef _UNICODE
        typeUnicode =      ( int ) 0x00400, // used in derived classes (e.g. CStdioFile) only
#endif
        modeCreate =       ( int ) 0x01000,
        modeNoTruncate =   ( int ) 0x02000,
        typeText =         ( int ) 0x04000, // used in derived classes (e.g. CStdioFile) only
        typeBinary =       ( int ) 0x08000, // used in derived classes (e.g. CStdioFile) only
        osNoBuffer =       ( int ) 0x10000,
        osWriteThrough =   ( int ) 0x20000,
        osRandomAccess =   ( int ) 0x40000,
        osSequentialScan = ( int ) 0x80000,
    };

    enum Attribute
    {
        normal     = 0x00,                // note: not same as FILE_ATTRIBUTE_NORMAL
        readOnly   = FILE_ATTRIBUTE_READONLY,
        hidden     = FILE_ATTRIBUTE_HIDDEN,
        system     = FILE_ATTRIBUTE_SYSTEM,
        volume     = 0x08,
        directory  = FILE_ATTRIBUTE_DIRECTORY,
        archive    = FILE_ATTRIBUTE_ARCHIVE,
        device     = FILE_ATTRIBUTE_DEVICE,
        temporary  = FILE_ATTRIBUTE_TEMPORARY,
        sparse     = FILE_ATTRIBUTE_SPARSE_FILE,
        reparsePt  = FILE_ATTRIBUTE_REPARSE_POINT,
        compressed = FILE_ATTRIBUTE_COMPRESSED,
        offline    = FILE_ATTRIBUTE_OFFLINE,
        notIndexed = FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
        encrypted  = FILE_ATTRIBUTE_ENCRYPTED
    };

    enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 };


// Constructors
    QFile();
    QFile( HANDLE hFile );
    QFile( const QString & lpszFileName, UINT nOpenFlags );
    ~QFile();


    operator HANDLE()const
    {
        return m_hFile;
    }
    operator bool() const
    {
        return nullptr != m_hFile;
    }


    bool		GetStatus( QFileStatus & rStatus ) const;
    QString		GetFileName() const;
    QString		GetFileTitle() const;
    QString		GetFilePath() const;
    OpenFlags	GetFileMode()const
    {
        return m_OpenMode;
    }
    void		SetFilePath( LPCTSTR lpszNewName );


// Operations
    bool			Open( LPCTSTR lpszFileName, UINT nOpenFlags, QError * pError = nullptr ) ;

    static void		Rename( LPCTSTR lpszOldName,	LPCTSTR lpszNewName );
    static void		Remove( LPCTSTR lpszFileName );
    static bool		GetStatus( LPCTSTR lpszFileName,	QFileStatus & rStatus );
    static void		SetStatus( LPCTSTR lpszFileName, const QFileStatus & status );



    ULONGLONG		Seek( LONGLONG offset, DWORD method );
    ULONGLONG		SeekToEnd();
    ULONGLONG		SeekToBegin();
    ULONGLONG		GetPosition() const;

    LONGLONG		GetFileSize() const;
    void			SetFileSize( ULONGLONG );



    virtual			bool IsClosed() const ;
    virtual			size_t Read( void * lpBuf, size_t nCount );
    virtual			size_t Write( const void * lpBuf, size_t nCount );



    //for binary files
    bool			Read(  void * data, DWORD nCount, DWORD & readed );
    bool			Write( const void * data, DWORD nCount, DWORD & writed );


    //for text files
    void			WriteLine( const QString & );
    bool			WriteString( const QString & str );
    bool			ReadString( QString  & s );



    bool LockRange( ULONGLONG dwPos, ULONGLONG dwCount );
    bool UnlockRange( ULONGLONG dwPos, ULONGLONG dwCount );


    void Abort();
    void Flush();
    void Close();

// Implementation
public:


    enum BufferCommand { bufferRead, bufferWrite, bufferCommit, bufferCheck };
    enum BufferFlags
    {
        bufferDirect = 0x01,
        bufferBlocking = 0x02
    };
    //virtual UINT GetBufferPtr(UINT nCommand, UINT nCount = 0, void** ppBufStart = nullptr, void** ppBufMax = nullptr){};

protected:

    // Attributes
    HANDLE		m_hFile;

    QString		m_strFileName;
    OpenFlags	m_OpenMode;

};







class QFindFile
{
    //_NO_COPY( QFindFile );
public:
    // Constructor.
    QFindFile();

    // Destructor.
    virtual ~QFindFile();

    // Attributes.
    ULONGLONG	GetFileSize()	const;
    bool		IsDots()		const;



    bool MatchesMask( UINT32 mask ) const
    {
        return ( ( m_findData.dwFileAttributes & mask ) != 0 );
    }
    bool IsArchived() const
    {
        return MatchesMask( FILE_ATTRIBUTE_ARCHIVE );
    }
    bool IsCompressed() const
    {
        return MatchesMask( FILE_ATTRIBUTE_COMPRESSED );
    }
    bool IsDirectory() const
    {
        return MatchesMask( FILE_ATTRIBUTE_DIRECTORY );
    }
    bool IsEncrypted() const
    {
        return MatchesMask( FILE_ATTRIBUTE_ENCRYPTED );
    }
    bool IsHidden() const
    {
        return MatchesMask( FILE_ATTRIBUTE_HIDDEN );
    }
    bool IsNormal() const
    {
        return MatchesMask( FILE_ATTRIBUTE_NORMAL );
    }
    bool IsOffline() const
    {
        return MatchesMask( FILE_ATTRIBUTE_OFFLINE );
    }
    bool IsReadOnly() const
    {
        return MatchesMask( FILE_ATTRIBUTE_READONLY );
    }
    bool HasReparsePoint() const
    {
        return MatchesMask( FILE_ATTRIBUTE_REPARSE_POINT );
    }
    bool IsSparse() const
    {
        return MatchesMask( FILE_ATTRIBUTE_SPARSE_FILE );
    }
    bool IsSystem() const
    {
        return MatchesMask( FILE_ATTRIBUTE_SYSTEM );
    }
    bool IsTemporary() const
    {
        return MatchesMask( FILE_ATTRIBUTE_TEMPORARY );
    }
    DWORD Attributes()const
    {
        return m_findData.dwFileAttributes;
    }

    BOOL GetLastWriteTime( FILETIME * pTimeStamp ) const;
    BOOL GetLastAccessTime( FILETIME * pTimeStamp ) const;
    BOOL GetCreationTime( FILETIME * pTimeStamp ) const;
    BOOL GetLastWriteTime( QTime & refTime ) const;
    BOOL GetLastAccessTime( QTime & refTime ) const;
    BOOL GetCreationTime( QTime & refTime ) const;



    QString GetFileName() const;
    QString GetFilePath() const;
    QString GetFolder() const;
    //QString GetFileTitle() const;


    // Implementation.
    void Close();
    bool FindFile( const QString & strName  );
    bool FindNextFile();


    const WIN32_FIND_DATA & GetData() const
    {
        return  m_findData;
    }

protected:
    QString				m_strBase;

    WIN32_FIND_DATA		m_findData; //hides WIN32_FIND_DATA
    HANDLE				m_hHandle;
    bool				m_bFoundFile;
    DWORD				m_dwDontShow;
};


//////////////////////////////////////////////////////////////////////////

class QSparseFile
{
public:
    static HANDLE	CreateSparseFile( LPCTSTR lpFileName );
    static BOOL		GetSparseFileSize( LPCTSTR lpFileName,  LARGE_INTEGER & liSparseFileSize, LARGE_INTEGER & liSparseFileCompressedSize );
    static bool		CopySparse( QString src, QString dest );
    static void		CopySparseRange( HANDLE hFrom, HANDLE hTo, LARGE_INTEGER iPos, LARGE_INTEGER iSize );

    static BOOL		VolumeSupportsSparseFiles( LPCTSTR lpRootPathName );
    static void		SetSparseRange( HANDLE hSparseFile, LONGLONG start, LONGLONG size );

    //foe secure delete
    static void		OverwriteSparseFile( HANDLE file,  LARGE_INTEGER iFileSize );
    static void		OverwriteRange( HANDLE hFile, LARGE_INTEGER iPos, LARGE_INTEGER iSize );
};


//reparse
//////////////////////////////////////////////////////////////////////////

class QReparsePoint
{

    HANDLE		m_hDir;

public:
    QReparsePoint( const QString & str , bool create = false );
    ~QReparsePoint();


    bool		IsValid() const
    {
        return m_hDir != INVALID_HANDLE_VALUE;
    }

    bool		GetReparsePoint( QString & target, DWORD * reparseTag = nullptr );
    bool		DeleteReparsePoint();


    bool		SetReparsePointJunction( QString target );
    int			GetNumberOfLinks();


    static bool	CreateDirectHardLink ( QString source,  QString target );
    static bool	CreateDirectSymLink( QString source,  QString target ) ;
    //bool		SetReparsePointSymlink(QString target);

    static bool	CreateMountPoint( QString source,  QString target );


    /*

    	GUID                    m_ReparseGuid;
    	DWORD const             m_Attr;
    	DWORD const             m_OpenFlags;
    	DWORD                   m_ReparseTag;


    	inline bool isReparsePoint() const
    	{
    		return (0 != (m_Attr & FILE_ATTRIBUTE_REPARSE_POINT));
    	}

    	inline bool isDirectory() const
    	{
    		return (0 != (m_Attr & FILE_ATTRIBUTE_DIRECTORY));
    	}

    	inline bool isVirtual() const
    	{
    		return (0 != (m_Attr & FILE_ATTRIBUTE_VIRTUAL));
    	}

    	inline bool isSymbolicLink() const // Vista++ symlink
    	{
    		return (IO_REPARSE_TAG_SYMLINK == m_ReparseTag);
    	}

    	inline bool isJunctionPoint() const
    	{
    		return (IO_REPARSE_TAG_MOUNT_POINT == m_ReparseTag);
    	}

    	inline bool isMicrosoftTag() const
    	{
    		return 0 != IsReparseTagMicrosoft(m_ReparseTag);
    	}
    */


};



}
}